
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/ledc.h"
#include "led_indicator_iot.h"  //源自esp-iot-solution-master的led_indicator组件，原始文件名为"led_indicator.h"  
#include "led_indicator_blink_default.h"
#include "esp_log.h"
#include "audio_pipeline.h"
#include "i2s_stream.h"
#include "raw_stream.h"
#include "tone_stream.h"
#include "mp3_decoder.h"
#include "filter_resample.h"
#include "board.h"
#include "esp_system.h"
#include "nvs_flash.h"

#include "I2S_Audio.h"
#include "Transport.h"
#include "iot_button.h"

#include "audio_tone_uri.h"
#include "wav_encoder.h"
#include "adc_battery.h"

static const char *TAG = "ES8311-WalkieTalkie";

#define PIN_BUTTON_PTT 12
#define LED_IO_NUM_13 13

bool speaking = 0; // 1=正在对外讲话，0=正在收听
bool recOver = 0;  // 接收完成标志位
bool sendDone = 1; // 发送完成标志位
int AUDIT_BIT = 16; //音频16Bit采样
//int count = 62;
audio_pipeline_handle_t pipeline_sender, pipeline_receiver;
audio_element_handle_t tone_stream_reader, mp3_decoder, i2s_stream_writer, i2s_stream_reader, raw_stream_writer, wav_encoder, raw_stream_reader, filter_upsample_el;
audio_event_iface_handle_t evt_reader, evt_writer, evt_battery;
periph_service_handle_t battery_service;
QueueHandle_t batteryQueue;
led_indicator_handle_t led_handle;
audio_board_handle_t board_handle;

static audio_element_handle_t create_filter(int source_rate, int source_channel, int dest_rate, int dest_channel, int mode)
{
    rsp_filter_cfg_t rsp_cfg = DEFAULT_RESAMPLE_FILTER_CONFIG();
    rsp_cfg.src_rate = source_rate;
    rsp_cfg.src_ch = source_channel;
    rsp_cfg.dest_rate = dest_rate;
    rsp_cfg.dest_ch = dest_channel;
    rsp_cfg.mode = mode;
    rsp_cfg.complexity = 0;
    return rsp_filter_init(&rsp_cfg);
}

/**
 * @brief  PTT按键松开
 */
static void button_speakDone_cb(void *arg)
{

    if (iot_button_get_event((button_handle_t)arg) == BUTTON_PRESS_UP)
    {
        speaking = 0;
        // audio_pipeline_pause(pipeline_sender);
        // audio_pipeline_reset_ringbuffer(pipeline_sender);
        // audio_pipeline_reset_elements(pipeline_sender);
        // audio_pipeline_resume(pipeline_sender);
        led_indicator_stop(led_handle, BLINK_UPDATING);
        gpio_set_level(LED_IO_NUM_13, 0);
        // ESP_LOGI(TAG, "Release button");
    }
}

/**
 * @brief  按下PTT按键
 */
static void button_speaking_cb(void *arg)
{

    if (iot_button_get_event((button_handle_t)arg) == BUTTON_PRESS_DOWN)
    {
        speaking = 1;
        led_indicator_start(led_handle, BLINK_UPDATING);
        // ESP_LOGI(TAG, "Press button");
    }
}

/**
 * @brief  espnow task
 */
static void dez_espnow_task(void *pvParameter)
{
    while (1)
    {

        if (speaking) // speaking status
        {

            if (sendDone) //上一次语音是否传输完成
            {
                //i2s_zero_dma_buffer(CONFIG_I2S_CH0);
                int samples_read = readVoice(samples_8bit, CONFIG_COUNT, raw_stream_reader); // 读取音频数据，8bit转换
                // printf("send voice address 1 %p",samples_8bit);
                sendVoice(samples_8bit, samples_read); // 发送音频数据

            }
        }
    }
}

void app_main(void)
{

    led_indicator_gpio_config_t led_indicator_gpio_config = {
        .gpio_num = LED_IO_NUM_13,
        .is_active_level_high = 0,
    };

    led_indicator_config_t led_config = {
        .led_indicator_gpio_config = &led_indicator_gpio_config,
        .mode = LED_GPIO_MODE,
        .blink_lists = (void *)NULL,
        .blink_list_num = 0,
    };

    led_handle = led_indicator_create(&led_config);
    // led_indicator_start(led_handle, BLINK_UPDATING);

     if (AUDIT_BIT == 32)
    {
        output_32bit = (uint32_t *)malloc(sizeof(uint32_t) * CONFIG_COUNT);
        samples_32bit = (uint32_t *)malloc(sizeof(uint32_t) * CONFIG_COUNT);
    }
    if (AUDIT_BIT == 16)
    {
        output_16bit = (uint16_t *)malloc(sizeof(uint16_t) * CONFIG_COUNT * 2);
        samples_16bit = (uint16_t *)malloc(sizeof(uint16_t) * CONFIG_COUNT * 2);
    }
    samples_8bit = (uint8_t *)malloc(sizeof(uint8_t) * CONFIG_COUNT * 4);
    // Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    // Button PTT definition
    button_config_t gpio_btnEnter_cfg = {
        .type = BUTTON_TYPE_GPIO,
        .gpio_button_config = {
            .gpio_num = PIN_BUTTON_PTT,
            .active_level = 0,
        },
    };
    button_handle_t gpio_btnEnter = iot_button_create(&gpio_btnEnter_cfg);

    if (NULL == gpio_btnEnter)
    {
        ESP_LOGE(TAG, "Button create failed");
    }

    // esp_log_level_set("*", ESP_LOG_INFO);
    // esp_log_level_set(TAG, ESP_LOG_DEBUG);

    ESP_LOGI(TAG, "Start codec chip");
    // audio_board_handle_t board_handle = audio_board_init();
    board_handle = audio_board_init();
    audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);

    ESP_LOGI(TAG, "Create audio pipeline");
    audio_pipeline_cfg_t pipeline_cfg_r = DEFAULT_AUDIO_PIPELINE_CONFIG();
    pipeline_sender = audio_pipeline_init(&pipeline_cfg_r);
    audio_pipeline_cfg_t pipeline_cfg_w = DEFAULT_AUDIO_PIPELINE_CONFIG();
    pipeline_receiver = audio_pipeline_init(&pipeline_cfg_w);

    tone_stream_cfg_t tone_cfg = TONE_STREAM_CFG_DEFAULT();
    tone_cfg.type = AUDIO_STREAM_READER;
    tone_stream_reader = tone_stream_init(&tone_cfg);
    AUDIO_NULL_CHECK(TAG, tone_stream_reader, return);

    mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG();
    mp3_decoder = mp3_decoder_init(&mp3_cfg);
    AUDIO_NULL_CHECK(TAG, mp3_decoder, return);

    filter_upsample_el = create_filter(16000, 1, 8000, 1, RESAMPLE_DECODE_MODE); //resample 16k mp3转换8k

    ESP_LOGI(TAG, "Create i2s stream to write data to codec chip");
    i2s_stream_cfg_t i2s_cfg_write = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg_write.type = AUDIO_STREAM_WRITER;
    i2s_cfg_write.i2s_config.sample_rate = CONFIG_SAMPLE_RATE;
    i2s_cfg_write.i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
    i2s_cfg_write.i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
    i2s_cfg_write.i2s_config.dma_buf_count = 2;
    i2s_cfg_write.i2s_config.dma_buf_len = 256;
    // i2s_cfg_write.use_alc = pdTRUE;
    i2s_stream_writer = i2s_stream_init(&i2s_cfg_write);

    ESP_LOGI(TAG, "Create i2s stream to read data from codec chip");
    i2s_stream_cfg_t i2s_cfg_read = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg_read.type = AUDIO_STREAM_READER;
    i2s_cfg_read.i2s_config.sample_rate = CONFIG_SAMPLE_RATE;
    i2s_cfg_read.i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
    i2s_cfg_read.i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
    i2s_cfg_read.i2s_config.dma_buf_count = 2;
    i2s_cfg_read.i2s_config.dma_buf_len = 256;
    //// i2s_cfg_read.out_rb_size=512;
    i2s_stream_reader = i2s_stream_init(&i2s_cfg_read);

    raw_stream_cfg_t raw_cfg_writer = {
        .out_rb_size = sizeof(uint32_t) * CONFIG_COUNT,
        .type = AUDIO_STREAM_WRITER,
    };
    raw_stream_writer = raw_stream_init(&raw_cfg_writer);

    raw_stream_cfg_t raw_cfg_reader = {
        .out_rb_size = sizeof(uint32_t) * CONFIG_COUNT,
        .type = AUDIO_STREAM_READER,
    };
    raw_stream_reader = raw_stream_init(&raw_cfg_reader);

    ESP_LOGI(TAG, "Register all elements to audio pipeline");

    audio_pipeline_register(pipeline_sender, i2s_stream_reader, "i2s_read");
    audio_pipeline_register(pipeline_sender, raw_stream_reader, "raw_read");
    audio_pipeline_register(pipeline_receiver, raw_stream_writer, "raw_write");
    audio_pipeline_register(pipeline_receiver, i2s_stream_writer, "i2s_write");
    audio_pipeline_register(pipeline_receiver, tone_stream_reader, "tone");
    audio_pipeline_register(pipeline_receiver, mp3_decoder, "mp3");
    audio_pipeline_register(pipeline_receiver, filter_upsample_el, "filter_upsample");

    // 3条音频路径：
    // 麦克风采集语音发送 [Mic]-->[i2s_stream_reader]-->[Raw_reader]--[espnow_send]
    // espnow接收语音并播放[espnow_receive]-->[Raw_writer]-->[i2s_stream_writer]-->[speaker]
    // 提示音播放 [tone]-->[mp3_decoder]-->[filter_sample]-->[i2s_stream_writer]-->[speaker]

    ESP_LOGI(TAG, "Link it together [codec_chip]-->i2s_stream_reader-->i2s_stream_writer-->[codec_chip]");
    const char *link_tag_tone[4] = {"tone", "mp3", "filter_upsample", "i2s_write"};
    audio_pipeline_link(pipeline_receiver, &link_tag_tone[0], 4);

    const char *link_tag_reader[2] = {"i2s_read", "raw_read"};
    audio_pipeline_link(pipeline_sender, &link_tag_reader[0], 2);
    const char *link_tag_writer[2] = {"raw_write", "i2s_write"};
    // audio_pipeline_link(pipeline_receiver, &link_tag_writer[0], 2);

    audio_element_set_uri(tone_stream_reader, tone_uri[TONE_TYPE_JIMUXIANSEN]);
    ESP_LOGI(TAG, "Set up  event listener");
    audio_event_iface_cfg_t evt_cfg_reader = AUDIO_EVENT_IFACE_DEFAULT_CFG();
    evt_reader = audio_event_iface_init(&evt_cfg_reader);

    audio_event_iface_cfg_t evt_cfg_writer = AUDIO_EVENT_IFACE_DEFAULT_CFG();
    evt_writer = audio_event_iface_init(&evt_cfg_writer);

    ESP_LOGI(TAG, "Listening event from all elements of pipeline");
    audio_pipeline_set_listener(pipeline_sender, evt_reader);
    audio_pipeline_set_listener(pipeline_receiver, evt_writer);

    //board_handle->audio_hal->audio_codec_set_volume(60); //function working
    audio_hal_set_volume(board_handle->audio_hal, 65);
    // board_handle->audio_hal->audio_codec_set_mute(true);

    // int v=0;
    // i2s_alc_volume_set(i2s_stream_writer, 0);
    // i2s_alc_volume_get(i2s_stream_writer,&v);
    //  board_handle->audio_hal->audio_codec_get_volume(&v);
    // ESP_LOGI(TAG, "音量:%d",v);

    ESP_LOGI(TAG, "Start audio_pipeline");
    
    audio_pipeline_run(pipeline_sender);
     vTaskDelay(1000 / portTICK_RATE_MS);// 扬声器上电延迟
    audio_pipeline_run(pipeline_receiver);

   
    //audio_pipeline_stop(pipeline_receiver);// pending issue test
    audio_pipeline_wait_for_stop(pipeline_receiver);
    
    audio_pipeline_breakup_elements(pipeline_receiver, i2s_stream_writer);
    audio_pipeline_relink(pipeline_receiver, &link_tag_writer[0], 2);
    audio_pipeline_set_listener(pipeline_receiver, evt_writer);
    audio_pipeline_run(pipeline_receiver);
    //audio_pipeline_resume(pipeline_receiver);

    ESP_LOGI(TAG, "Listen for all pipeline events");

    iot_button_register_cb(gpio_btnEnter, BUTTON_PRESS_DOWN, button_speaking_cb, NULL);
    iot_button_register_cb(gpio_btnEnter, BUTTON_PRESS_UP, button_speakDone_cb, NULL);

     dez_wifi_init();
     dez_espnow_init();
     xTaskCreate(dez_espnow_task, "dez_espnow_task", 2048, NULL, 0, NULL);

    ESP_LOGI(TAG, "Battery detection");
    vol_adc_param_t adc_cfg = {
        .unit = ADC_UNIT_1,
        .chan = ADC1_CHANNEL_6,
        .ratio = 2.0,
        .width = ADC_WIDTH_BIT_12,
        .atten = ADC_ATTEN_11db,
        .v_ref = 1100,
    };

    vol_monitor_param_t vol_monitor_cfg = {
        .init = adc_init,
        .deinit = adc_deinit,
        .vol_get = vol_read,
        .read_freq = 300,  // 读电压vol_read()间隔
        .report_freq = 1, // battery_service_cb 触发间隔
        .vol_full_threshold = 4200,
        .vol_low_threshold = 3500,
    };

    vol_monitor_cfg.user_data = audio_calloc(1, sizeof(vol_adc_param_t));
    AUDIO_MEM_CHECK(TAG, vol_monitor_cfg.user_data, return);
    memcpy(vol_monitor_cfg.user_data, &adc_cfg, sizeof(vol_adc_param_t));

    ESP_LOGI(TAG, "[1.0] create battery service");
    battery_service_config_t config = BATTERY_SERVICE_DEFAULT_CONFIG();
    config.evt_cb = battery_service_cb;
    config.vol_monitor = vol_monitor_create(&vol_monitor_cfg);
    batteryQueue = xQueueCreate(1, sizeof(int));

    config.cb_ctx = (void *)batteryQueue;

    battery_service = battery_service_create(&config);

    ESP_LOGI(TAG, "[1.1] start battery service");
    if (periph_service_start(battery_service) != ESP_OK)
    {
        ESP_LOGI(TAG, "destroy battery service");
        periph_service_destroy(battery_service);
        vol_monitor_destroy(config.vol_monitor);
        free(vol_monitor_cfg.user_data);
    }


    ESP_LOGI(TAG, "[1.2] start battery voltage report");
    battery_service_vol_report_switch(battery_service, true);

    while (1)
    {
        int batResult = 0;
        BaseType_t xStatus;
        xStatus = xQueueReceive(batteryQueue, &batResult, 100);
        if (xStatus == pdPASS)
        {
            ESP_LOGI(TAG, "battery status success");
            if (batResult == 1)
            {
                ESP_LOGI(TAG, "Low power");
                speaking = 0;
                // 切换pipeline播放低电量提示
                //vTaskDelay(4000 / portTICK_RATE_MS);
                //audio_pipeline_pause(pipeline_receiver);
                audio_pipeline_stop(pipeline_receiver);
                audio_pipeline_wait_for_stop(pipeline_receiver);
                audio_element_set_uri(tone_stream_reader, tone_uri[TONE_TYPE_LOW_POWER]);
                audio_pipeline_breakup_elements(pipeline_receiver, i2s_stream_writer);
                audio_pipeline_relink(pipeline_receiver, &link_tag_tone[0], 4);
                audio_pipeline_set_listener(pipeline_receiver, evt_writer);
                audio_pipeline_run(pipeline_receiver);
                //audio_pipeline_resume(pipeline_receiver);
                //ESP_LOGI(TAG, "Low power2");
                //vTaskDelay(4000 / portTICK_RATE_MS);
               
                // 重新切换回对讲语音监听
                //audio_pipeline_stop(pipeline_receiver);
                audio_pipeline_wait_for_stop(pipeline_receiver);
                // audio_pipeline_pause(pipeline_receiver);
                audio_pipeline_breakup_elements(pipeline_receiver, i2s_stream_writer);
                audio_pipeline_relink(pipeline_receiver, &link_tag_writer[0], 2);
                audio_pipeline_set_listener(pipeline_receiver, evt_writer);
                audio_pipeline_run(pipeline_receiver);

                batResult = 0;
            }
        }
        

       
        // audio_event_iface_msg_t msg, bat_msg;
        // esp_err_t ret = audio_event_iface_listen(evt_reader, &msg, 200); //30000 portMAX_DELAY
        // if (ret != ESP_OK)
        // {
        //     ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
        //     continue;
        // }
    
        /* Stop when the last pipeline element (i2s_stream_writer in this case) receives stop event */
        //  if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *)raw_stream_reader && msg.cmd == AEL_MSG_CMD_REPORT_STATUS && (((int)msg.data == AEL_STATUS_STATE_STOPPED) || ((int)msg.data == AEL_STATUS_STATE_FINISHED)))
        //  {
        //      ESP_LOGW(TAG, "[ * ] Stop event received");
        //      break;
        //  }
    }

    ESP_LOGI(TAG, "Stop audio_pipeline");
    audio_pipeline_stop(pipeline_sender);
    audio_pipeline_wait_for_stop(pipeline_sender);
    audio_pipeline_terminate(pipeline_sender);

    audio_pipeline_stop(pipeline_receiver);
    audio_pipeline_wait_for_stop(pipeline_receiver);
    audio_pipeline_terminate(pipeline_receiver);

    audio_pipeline_unregister(pipeline_sender, raw_stream_reader);
    audio_pipeline_unregister(pipeline_sender, i2s_stream_reader);

    audio_pipeline_unregister(pipeline_receiver, raw_stream_write);
    audio_pipeline_unregister(pipeline_receiver, i2s_stream_writer);

    /* Terminate the pipeline before removing the listener */
    audio_pipeline_remove_listener(pipeline_sender);
    audio_pipeline_remove_listener(pipeline_receiver);

    /* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are called before destroying event_iface */
    audio_event_iface_destroy(evt_reader);
    audio_event_iface_destroy(evt_writer);

    /* Release all resources */
    audio_pipeline_deinit(pipeline_sender);
    audio_element_deinit(raw_stream_reader);
    audio_element_deinit(i2s_stream_reader);

    audio_pipeline_deinit(pipeline_receiver);
    audio_element_deinit(raw_stream_writer);
    audio_element_deinit(i2s_stream_writer);
    if (AUDIT_BIT == 32)
    {
        free(output_32bit);
        output_32bit = NULL;
    }
    if (AUDIT_BIT == 16)
    {
        free(output_16bit);
        output_16bit = NULL;
    }
}
